package me.flyray.bsin.server.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.extern.slf4j.Slf4j;
import me.flyray.bsin.domain.entity.Transaction;
import me.flyray.bsin.domain.enums.TransactionStatus;
import me.flyray.bsin.dubbo.invoke.BsinServiceInvoke;
import me.flyray.bsin.infrastructure.mapper.TransactionJournalMapper;
import me.flyray.bsin.infrastructure.mapper.TransactionMapper;
import me.flyray.bsin.infrastructure.biz.paychannel.PayChannelConfigBiz;
import me.flyray.bsin.payment.channel.wxpay.BsinWxPayServiceUtil;
import me.flyray.bsin.payment.channel.wxpay.WxServiceUtil;
import org.apache.shenyu.client.apidocs.annotations.ApiDoc;
import org.apache.shenyu.client.apidocs.annotations.ApiModule;
import org.apache.shenyu.client.springmvc.annotation.ShenyuSpringMvcClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/refundCallback")
@ShenyuSpringMvcClient("/refundCallback/**")
@ApiModule(value = "refundCallback")
@Slf4j
public class RefundCallbackController {

  @Autowired private BsinServiceInvoke bsinServiceInvoke;

  @Autowired BsinWxPayServiceUtil bsinWxPayServiceUtil;
  @Autowired private TransactionMapper transactionMapper;
  @Autowired private TransactionJournalMapper waasTransactionJournalMapper;
  @Autowired private PayChannelConfigBiz payChannelConfigBiz;

  /**
   * 微信退款回调处理（完全兼容 v2 和 v3，支持服务商、普通商户、特约商户）
   *
   * <p>支持的回调类型： 1. 普通商户退款回调（v2/v3） 2. 服务商子商户退款回调（v2/v3） 3. 特约商户退款回调（v2/v3）
   *
   * <p>处理流程： 1. 根据 outRefundNo 查询退款订单信息 2. 获取支付渠道配置 3. 解析回调数据（自动识别 v2/v3） 4. 验证签名和更新退款状态 5.
   * 调用oms模块处理退款业务
   *
   * <p>参考：https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_16
   *
   * @param body 回调数据
   * @param outRefundNo 商户退款单号
   * @return
   * @throws Exception
   */
  @PostMapping("/wxpay/{outRefundNo}")
  @ApiDoc(desc = "wxpay")
  public Object wxpay(
      @RequestBody(required = false) String body,
      @PathVariable("outRefundNo") String outRefundNo,
      @RequestHeader Map<String, String> headers)
      throws Exception {
    WxPayRefundNotifyResult result = null;
    WxPayRefundNotifyV3Result wxPayRefundNotifyV3Result = null;
    try {
      log.info("微信退款回调开始处理，outRefundNo: {}", outRefundNo);
      log.info("回调数据body: {}", body);
      log.info("回调头headers: {}", headers);

      // 1、根据 outRefundNo 查询退款订单信息
      Transaction refundTransaction =
          transactionMapper.selectOne(
              new LambdaQueryWrapper<Transaction>().eq(Transaction::getOutOrderNo, outRefundNo));

      if (refundTransaction == null) {
        log.error("未找到对应的退款订单，outRefundNo: {}", outRefundNo);
        return WxPayNotifyResponse.fail("退款订单不存在");
      }

      log.info("查询到退款订单: {}", refundTransaction);

      // 2、根据订单信息查询支付渠道配置
      String payChannelConfigNo = refundTransaction.getPayChannelConfigNo();
      if (payChannelConfigNo == null || payChannelConfigNo.isEmpty()) {
        log.error("退款订单未关联支付渠道配置，outRefundNo: {}", outRefundNo);
        return WxPayNotifyResponse.fail("支付渠道配置不存在");
      }

      log.info("支付渠道配置编号: {}", payChannelConfigNo);

      // 3、获取微信支付服务（支持 v2 和 v3）
      WxServiceUtil wxServiceUtil = payChannelConfigBiz.getWxServiceWrapper(payChannelConfigNo);
      WxPayService wxPayService = wxServiceUtil.getWxPayService();

      // 获取支付渠道配置信息
      var payChannelConfig = payChannelConfigBiz.getPayChannelConfig(payChannelConfigNo);
      if (payChannelConfig == null) {
        log.error("未找到支付渠道配置，payChannelConfigNo: {}", payChannelConfigNo);
        return WxPayNotifyResponse.fail("支付渠道配置不存在");
      }

      Map<String, Object> requestMap = new HashMap<>();

      // 4、智能解析微信退款回调数据（根据配置自动识别版本和商户模式）
      if ("V3".equals(wxServiceUtil.getApiVersion())) {
        log.info("微信退款V3回调");
        SignatureHeader header =
            SignatureHeader.builder()
                .timeStamp(headers.get("wechatpay-timestamp"))
                .nonce(headers.get("wechatpay-nonce"))
                .signature(headers.get("wechatpay-signature"))
                .serial(headers.get("wechatpay-serial"))
                .build();
        wxPayRefundNotifyV3Result = wxPayService.parseRefundNotifyV3Result(body, header);
        log.info("微信退款回调结果：{}", wxPayRefundNotifyV3Result.getResult().toString());
        WxPayRefundNotifyV3Result.DecryptNotifyResult decryptNotifyResult =
            wxPayRefundNotifyV3Result.getResult();
        requestMap.put("refundStatus", decryptNotifyResult.getRefundStatus());
        requestMap.put("outOrderNo", decryptNotifyResult.getOutTradeNo());
        requestMap.put("refundNo", decryptNotifyResult.getOutRefundNo());
        requestMap.put("refundId", decryptNotifyResult.getRefundId());
        requestMap.put("transactionId", decryptNotifyResult.getTransactionId());
        requestMap.put("totalFee", decryptNotifyResult.getAmount().getTotal());
        requestMap.put("refundFee", decryptNotifyResult.getAmount().getRefund());
        requestMap.put("successTime", decryptNotifyResult.getSuccessTime());
        requestMap.put("userReceivedAccount", decryptNotifyResult.getUserReceivedAccount());
        //        requestMap.put("channel", decryptNotifyResult.getChannel());
        //        requestMap.put("fundsAccount", decryptNotifyResult.getFundsAccount());

        // V3接口验证微信退款通知参数
        if (decryptNotifyResult.getRefundStatus() == null) {
          log.error("微信退款V3回调解析失败，refundStatus为空");
          return WxPayNotifyResponse.fail("退款回调解析失败");
        }
      } else {
        log.info("微信退款V2回调");
        result = wxPayService.parseRefundNotifyResult(body);
        log.info("退款回调结果: {}", JSONObject.toJSONString(result));
        //        requestMap.put("resultCode", result.getRefundStatus());
        //        requestMap.put("orderNo", result.getOutTradeNo());
        //        requestMap.put("refundNo", result.getOutRefundNo());
        //        requestMap.put("refundId", result.getRefundId());
        //        requestMap.put("transactionId", result.getTransactionId());
        //        requestMap.put("totalFee", result.getTotalFee());
        //        requestMap.put("refundFee", result.getRefundFee());
        //        requestMap.put("successTime", result.getSuccessTime());
        //        requestMap.put("userReceivedAccount", result.getUserReceivedAccount());
        //        requestMap.put("channel", result.getChannel());
        //        requestMap.put("fundsAccount", result.getFundsAccount());
      }

      if (result == null && wxPayRefundNotifyV3Result == null) {
        log.error("微信退款回调解析失败，无法识别回调格式");
        return WxPayNotifyResponse.fail("退款回调解析失败");
      }

      // 添加商户模式信息
      requestMap.put("merchantPayMode", payChannelConfig.getMerchantPayMode());
      requestMap.put("payWay", payChannelConfig.getPayWay());
      requestMap.put("bizRoleAppId", payChannelConfig.getBizRoleAppId());
      requestMap.put("bizRoleTypeNo", payChannelConfig.getBizRoleTypeNo());

      // 5、验证更新退款状态
      Transaction updatedRefundTransaction =
          updateRefundTransactionStatus(requestMap, refundTransaction);
      if (updatedRefundTransaction == null) {
        log.warn("未找到对应的退款记录，退款单号：{}", outRefundNo);
        return WxPayNotifyResponse.fail("未找到退款记录");
      }

      // 6、异步调用（泛化调用解耦）退款完成方法统一处理： 根据退款类型后续处理
      bsinServiceInvoke.genericInvoke(
          "UnifyRefundOrderService", "completeRefund", "dev", requestMap);

      log.info("微信退款回调处理完成，退款单号: {}", outRefundNo);

    } catch (Exception e) {
      log.error(
          "微信退款回调处理失败，outRefundNo: {}, 错误信息: {}",
          outRefundNo != null ? outRefundNo : "未知",
          e.getMessage(),
          e);
      return WxPayNotifyResponse.fail("退款处理失败");
    }
    return WxPayNotifyResponse.success("success");
  }

  /** 更新退款交易状态 */
  //  @Transactional(rollbackFor = Exception.class)
  protected Transaction updateRefundTransactionStatus(
      Map<String, Object> requestMap, Transaction refundTransaction) {

    log.info("更新退款交易状态requestMap: {}", requestMap);
    String resultCode = (String) requestMap.get("resultCode");
    String refundNo = (String) requestMap.get("refundNo");
    String refundId = (String) requestMap.get("refundId");
    String transactionId = (String) requestMap.get("transactionId");
    Integer totalFee = (Integer) requestMap.get("totalFee");
    Integer refundFee = (Integer) requestMap.get("refundFee");
    String successTime = (String) requestMap.get("successTime");
    String userReceivedAccount = (String) requestMap.get("userReceivedAccount");
    String channel = (String) requestMap.get("channel");
    String fundsAccount = (String) requestMap.get("fundsAccount");

    if (refundTransaction == null) {
      return null;
    }

    // 更新退款状态
    if ("SUCCESS".equals(resultCode)) {
      refundTransaction.setTransactionStatus(TransactionStatus.SUCCESS.getCode());
      // 更新实际退款金额（微信返回的是分，需要转换为元）
      if (refundFee != null) {
        BigDecimal actualRefundAmount =
            new BigDecimal(refundFee).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP);
        refundTransaction.setTxAmount(actualRefundAmount);
      }

      // 更新交易流水状态
      waasTransactionJournalMapper.updateTransferStatus(
          refundTransaction.getSerialNo(), TransactionStatus.SUCCESS.getCode());

      log.info(
          "退款成功，退款单号: {}, 微信退款单号: {}, 实际退款金额: {}",
          refundNo,
          refundId,
          refundTransaction.getTxAmount());
    } else {
      refundTransaction.setTransactionStatus(TransactionStatus.FAIL.getCode());

      // 更新交易流水状态
      waasTransactionJournalMapper.updateTransferStatus(
          refundTransaction.getSerialNo(), TransactionStatus.FAIL.getCode());

      log.warn("退款失败，退款单号: {}, 状态: {}", refundNo, resultCode);
    }

    // 更新退款记录
    transactionMapper.updateById(refundTransaction);
    return refundTransaction;
  }

  /** 支付宝退款回调接口（预留） */
  @PostMapping("/alipay/{outRefundNo}")
  @ApiDoc(desc = "alipay")
  public Object alipay(
      @RequestBody(required = false) String body, @PathVariable("outRefundNo") String outRefundNo)
      throws Exception {
    // TODO: 实现支付宝退款回调处理
    log.info("支付宝退款回调，outRefundNo: {}", outRefundNo);
    return "success";
  }

  /** 银联退款回调接口（预留） */
  @PostMapping("/unionpay/{outRefundNo}")
  @ApiDoc(desc = "unionpay")
  public Object unionpay(
      @RequestBody(required = false) String body, @PathVariable("outRefundNo") String outRefundNo)
      throws Exception {
    // TODO: 实现银联退款回调处理
    log.info("银联退款回调，outRefundNo: {}", outRefundNo);
    return "success";
  }
}
